package com.nightonke.boommenu;

import ohos.eventhandler.EventHandler;
import ohos.aafwk.ability.Ability;
import ohos.agp.components.AttrHelper;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.app.Context;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Texture;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.eventhandler.EventRunner;
import ohos.global.resource.NotExistException;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.solidxml.Theme;
import ohos.global.resource.WrongTypeException;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.image.common.Size;
import ohos.media.image.PixelMap;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Random;

/**
 * Created by Weiping Huang at 01:12 on 2016/3/19
 * For Personal Open Source
 * Contact me at 2584541288@qq.com or nightonke@outlook.com
 *
 */

public final class Util {

    public static final HiLogLabel LABEL_LOG =
            new HiLogLabel(HiLog.LOG_APP, 0x00001, BoomMenuButton.TAG);

    private static Context context;
    public static void setContext(Context c)
    {
        context = c;
    }

    static Ability scanForActivity(Context contextIn) {
        if (contextIn == null) {
            HiLog.warn(LABEL_LOG, "scanForActivity: context is null!");
            return null;
        } else if (contextIn instanceof Ability)
            return (Ability)contextIn;
        HiLog.warn(LABEL_LOG, "scanForActivity: context is null!");
        return null;
    }
    static ComponentContainer scanTopComponentContainer(Component component)
    {
        ComponentContainer container = null;
        try {
            container = (ComponentContainer) component.getComponentParent();
            if (container != null) {
                if (container.getComponentParent() == null) {
                    return container;
                } else {
                    return scanTopComponentContainer(container);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return container;
    }
    static void setVisibility(int visibility, Component... views) {
        for (Component view : views) if (view != null) view.setVisibility(visibility);
    }

    private static EventHandler eventHandler;

    private static EventRunner runner;

    public static int dp2px(float dp){
        if(context != null) {
            return AttrHelper.vp2px(dp, context);
        }
        else {
            return AttrHelper.vp2px(dp, (float)1.5);
        }
    }

    public static Color getColor(Component view, int id, Theme theme) {
        Color color = new Color();
        try {
            color =  new Color(view.getContext().getResourceManager().getElement(id).getColor());
        }
        catch (NotExistException | IOException | WrongTypeException e)
        {
            e.printStackTrace();
        }
        finally {
            return color;
        }
    }

    public static Color getColor(ResourceManager resourceManager, int id, Theme theme) {
        //noinspection deprecation
        Color color = new Color();
        try {
            color =  new Color(resourceManager.getElement(id).getColor());
        }
        catch (NotExistException | IOException | WrongTypeException e)
        {
            e.printStackTrace();
        }
        finally {
            return color;
        }
    }

    public static Color getColor(Component view, int id) {
        return getColor(view, id, null);
    }

    public static Color getColor(ResourceManager resourceManager, int id) {
        return getColor(resourceManager, id, null);
    }

    public static Element getSystemDrawable(Context contextIn, int id) {
//        int[] attrs = new int[] { id };
//        TypedArray ta = context.obtainStyledAttributes(attrs);
//        Element drawable = ta.getDrawable(0);
//        ta.recycle();
        ShapeElement drawable = new ShapeElement(contextIn, id);
        return drawable;
    }

    public static Element getDrawable(Component view, int id, Theme theme){
        //noinspection deprecation
        return new ShapeElement(view.getContext(), id);
    }

    public static void setDrawable(Image image, int id, Element drawable) {
        if (image == null) return;
        if (id == 0) {
            if (drawable != null) image.setImageElement(drawable);
        } else image.setPixelMap(id);
    }

    public static void setText(Text textView, int id, String text) {
        try {
            if (textView == null) return;
            if (id == 0) {
                if (text != null && !text.equals(textView.getText())) textView.setText(text);
            } else {
                CharSequence oldText = textView.getContext().getResourceManager().getElement(id).getString();
                if (!oldText.equals(textView.getText())) textView.setText(id);
            }
        }
        catch (NotExistException e)
        {
            e.printStackTrace();
        }
        catch (WrongTypeException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    public static void setTextColor(Text textView, int id, Color color) {
        if (textView == null) return;
        if (id == 0) {
            textView.setTextColor(color);
        } else textView.setTextColor(getColor(textView.getContext(), id));
    }

    public static Element getDrawable(Component view, int id) {
        //noinspection deprecation
        return new ShapeElement(view.getContext(), id);
    }

    public static ShapeElement getOvalDrawable(Component view, Color color) {
        ShapeElement gradientDrawable = (ShapeElement) getDrawable(
                view,
                ResourceTable.Graphic_shape_oval_normal);
        gradientDrawable.setRgbColor(RgbColor.fromArgbInt(color.getValue()));
        return gradientDrawable;
    }

    public static PixelMapElement getOvalBitmapDrawable(Component view, int radius, Color color) {
        if (radius <= 0) {
            return null;
        }
        PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
        options.size = new Size(2 * radius, 2 * radius);
        PixelMap bitmap = PixelMap.create(options);
        Texture texture = new Texture(bitmap);

        Canvas canvasPressed = new Canvas(texture);
        Paint paintPressed = new Paint();
        paintPressed.setAntiAlias(true);
        paintPressed.setColor(color);
        canvasPressed.drawCircle(
                radius,
                radius,
                radius, paintPressed);
        return new PixelMapElement(bitmap);
    }

    public static ShapeElement getRectangleDrawable(Component view, int cornerRadius, Color color) {
        ShapeElement gradientDrawable = (ShapeElement) getDrawable(
                view,
                ResourceTable.Graphic_shape_rectangle_normal);
        gradientDrawable.setCornerRadius(cornerRadius);
        gradientDrawable.setRgbColor(RgbColor.fromArgbInt(color.getValue()));
        return gradientDrawable;
    }

    public static PixelMapElement getRectangleBitmapDrawable(Component view, int width, int height, int cornerRadius, Color color) {
        if (width <= 0 || height <= 0) {
            return null;
        }
        PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
        options.size = new Size(width, height);
        PixelMap bitmap = PixelMap.create(options);
        Texture texture = new Texture(bitmap);
        Canvas canvasPressed = new Canvas(texture);
        Paint paintPressed = new Paint();
        paintPressed.setAntiAlias(true);
        paintPressed.setColor(color);
        canvasPressed.drawRoundRect(new RectFloat(0, 0, width, height), cornerRadius, cornerRadius, paintPressed);
        return new PixelMapElement(bitmap);
    }

    public static float distance(Point a, Point b) {
        return (float) Math.sqrt((a.getPointXToInt() - b.getPointXToInt()) * (a.getPointXToInt() - b.getPointXToInt()) +
                (a.getPointYToInt() - b.getPointYToInt()) * (a.getPointYToInt() - b.getPointYToInt()));
    }

    // Bitmap drawable in state-list drawable is able to perform a click-effect.
    public static StateElement getOvalStateListBitmapDrawable(Component view,
                                                             int radius,
                                                             Color normalColor,
                                                             Color highlightedColor,
                                                             Color unableColor) {
        StateElement stateListDrawable = new StateElement();
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_PRESSED},
                getOvalBitmapDrawable(view, radius, highlightedColor));
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_DISABLED},
                getOvalBitmapDrawable(view, radius, unableColor));
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_EMPTY},
                getOvalBitmapDrawable(view, radius, normalColor));
        return stateListDrawable;
    }

    // Gradient drawable in state-list drawable is not able to perform a click-effect.
    public static StateElement getOvalStateListGradientDrawable(Component view,
                                                                     Color normalColor,
                                                                     Color highlightedColor,
                                                                     Color unableColor) {
        StateElement stateListDrawable = new StateElement();
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_PRESSED},
                getOvalDrawable(view, highlightedColor));
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_DISABLED},
                getOvalDrawable(view, unableColor));
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_EMPTY},
                getOvalDrawable(view, normalColor));
        return stateListDrawable;
    }

    // Bitmap drawable in state-list drawable is able to perform a click-effect.
    public static StateElement getRectangleStateListBitmapDrawable(Component view,
                                                                        int width,
                                                                        int height,
                                                                        int cornerRadius,
                                                                        Color normalColor,
                                                                        Color highlightedColor,
                                                                        Color unableColor) {
        StateElement stateListDrawable = new StateElement();
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_PRESSED},
                getRectangleBitmapDrawable(view, width, height, cornerRadius, highlightedColor));
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_DISABLED},
                getRectangleBitmapDrawable(view, width, height, cornerRadius, unableColor));
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_EMPTY},
                getRectangleBitmapDrawable(view, width, height, cornerRadius, normalColor));
        return stateListDrawable;
    }

    // Gradient drawable in state-list drawable is not able to perform a click-effect.
    public static StateElement getRectangleStateListGradientDrawable(Component view,
                                                                          int cornerRadius,
                                                                          Color normalColor,
                                                                          Color highlightedColor,
                                                                          Color unableColor) {
        StateElement stateListDrawable = new StateElement();
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_PRESSED},
                getRectangleDrawable(view, cornerRadius, highlightedColor));
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_DISABLED},
                getRectangleDrawable(view, cornerRadius, unableColor));
        stateListDrawable.addState(
                new int[]{ComponentState.COMPONENT_STATE_EMPTY},
                getRectangleDrawable(view, cornerRadius, normalColor));
        return stateListDrawable;
    }

    public static int getInt(
            ResourceManager resManager,
            int id,
            int defaultId) throws NotExistException, WrongTypeException, IOException {
        int ret;
        try
        {
            ret = resManager.getElement(id).getInteger();
        }
        catch (Exception e)
        {
            ret = resManager.getElement(defaultId).getInteger();
        }
        return ret;
    }

    public static boolean getBoolean(
            ResourceManager resManager,
            int id,
            int defaultId) throws NotExistException, WrongTypeException, IOException {
        boolean ret;
        try
        {
            ret = resManager.getElement(id).getBoolean();
        }
        catch (Exception e)
        {
            ret = resManager.getElement(defaultId).getBoolean();
        }
        return ret;
    }

    public static int getDimenSize(
            ResourceManager resManager,
            int id,
            int defaultId) throws NotExistException, WrongTypeException, IOException {
        int ret;
        try
        {
            ret = (int)resManager.getElement(id).getFloat();
        }
        catch (Exception e)
        {
            ret = (int)resManager.getElement(defaultId).getFloat();
        }
        return ret;
    }

    public static int getDimenOffset(
            ResourceManager resManager,
            int id,
            int defaultId) throws NotExistException, WrongTypeException, IOException {
        int ret;
        try
        {
            ret = (int)resManager.getElement(id).getFloat();
        }
        catch (Exception e)
        {
            ret = (int)resManager.getElement(defaultId).getFloat();
        }
        return ret;
    }

    public static Color getColor(
            ResourceManager resManager,
            int id,
            int defaultId) {
        int ret = 0;
        try
        {
            ret = resManager.getElement(id).getColor();
        }
        catch (NotExistException e)
        {
            ret = resManager.getElement(defaultId).getColor();
        }
        catch (WrongTypeException e)
        {
            ret = resManager.getElement(defaultId).getColor();
        }
        catch (IOException e)
        {
            ret = resManager.getElement(defaultId).getColor();
        }
        finally {
            return new Color(ret);
        }
    }

    public static Color getColor(Context contextIn, int id) {
        Color ret = new Color();
        try {
            //noinspection deprecation
            ret = new Color(contextIn.getResourceManager().getElement(id).getColor());
        }
        catch (NotExistException e)
        {
            e.printStackTrace();
        }
            catch (WrongTypeException e)
        {
            e.printStackTrace();
        }
            catch (IOException e)
        {
            e.printStackTrace();
        }
        finally {
            return ret;
        }
    }

    public static Color getColor(Context contextIn, int id, Color color) {
        if (id == 0) return color;
        else {
            return getColor(contextIn, id);
        }
    }

    public static void setDrawable(Component view, Element drawable) {
        view.setBackground(drawable);
    }

    public static Color getDarkerColor(Color color) {
        RgbColor rgbColor = RgbColor.fromArgbInt(color.getValue());
        rgbColor.setBlue((int)(rgbColor.getBlue() * 0.9f));
        return new Color(rgbColor.asArgbInt());
    }

    public static Color getLighterColor(Color color) {
        RgbColor rgbColor = RgbColor.fromArgbInt(color.getValue());
        rgbColor.setBlue((int)(rgbColor.getBlue() * 1.1f));
        return new Color(rgbColor.asArgbInt());
    }

    private static final int[] colors = new int[] {
            Color.getIntColor("#F44336"),
            Color.getIntColor("#E91E63"),
            Color.getIntColor("#9C27B0"),
            Color.getIntColor("#673AB7"),
            Color.getIntColor("#3F51B5"),
            Color.getIntColor("#2196F3"),
            Color.getIntColor("#03A9F4"),
            Color.getIntColor("#00BCD4"),
            Color.getIntColor("#009688"),
            Color.getIntColor("#4CAF50"),
            Color.getIntColor("#009688"),
            Color.getIntColor("#CDDC39"),
            Color.getIntColor("#FFEB3B"),
            Color.getIntColor("#FF9800"),
            Color.getIntColor("#FF5722"),
            Color.getIntColor("#795548"),
            Color.getIntColor("#9E9E9E"),
            Color.getIntColor("#607D8B"),
    };

    private static final ArrayList<Integer> usedColor = new ArrayList<>();

    public static Color getColor() {
        Random random = new Random();
        while (true) {
            int colorIndex = random.nextInt(colors.length);
            if (!usedColor.contains(colorIndex)) {
                usedColor.add(colorIndex);
                while (usedColor.size() > 6) usedColor.remove(0);
                return new Color(colors[colorIndex]);
            }
        }
    }

    public static boolean pointInView(Point point, Component view) {
        return view.getLeft() <= point.getPointX() && point.getPointX() <= view.getRight() &&
               view.getTop() <= point.getPointY() && point.getPointY() <= view.getBottom();
    }

    public static <T> Component invokeProperty(Component component, String propertyName, T value) {
        try {
            for (int i = 0; i < component.getClass().getMethods().length; i++) {
                Method f = component.getClass().getMethods()[i];
                String methodName = f.getName();
                if (methodName.startsWith("set") && methodName.equalsIgnoreCase("set"+propertyName)) {
                    HiLog.info(LABEL_LOG,f.getName() + " = ");
                    String o = f.invoke(component, value) == null ? "" : f.invoke(component, value).toString();
                    HiLog.info(LABEL_LOG, o);
                }
            }
        }
        catch (InvocationTargetException e)
        {
            HiLog.error(LABEL_LOG, e.getMessage());
        }
        catch (IllegalAccessException e)
        {
            HiLog.error(LABEL_LOG, e.getMessage());
        }
        finally {
            return component;
        }
    }

    public static EventHandler commonEventHandler()
    {
        if(runner == null)
        {
            runner = EventRunner.getMainEventRunner();
        }
        if(eventHandler == null)
        {
            eventHandler = new EventHandler(runner);
        }
        return eventHandler;
    }

    private static Util ourInstance = new Util();

    public static Util getInstance() {
        return ourInstance;
    }

    private Util() {
    }
}
